﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ICU
{
    public abstract class IServer
    {
        virtual public Dictionary<string, Plugin> Plugins { get; protected set; } = new Dictionary<string, Plugin>();
        virtual public List<long> Banlist { get; protected set; }
        virtual public Dictionary<long, User> Users { get; }
        virtual public Dictionary<long, Group> Groups { get; }
        virtual public object configuration { get; protected set; }
        public abstract Message SendSystemMessage(long to, string msg);
        public virtual void ReloadPlugin(string name = "")
        {
            if (name == "")
            {
                onPluginDisable(new PluginDisableEventArgs());
                onPluginEnable(new PluginEnableEventArgs());
            }
            else
            {
                foreach (var item in PluginDisableEvent.GetInvocationList())
                {
                    if (((Plugin)item.Target).Name == name)
                    {
                        try
                        {
                            item.Method?.Invoke(item, new object[] { this, new PluginDisableEventArgs() });
                        }
                        catch (Exception e) { GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'."); if (!Plugins.ContainsKey(((Plugin)item.Target).Name)) { PluginDisableEvent -= item as EventHandler<PluginDisableEventArgs>; } }
                    }
                }
                foreach (var item in PluginEnableEvent.GetInvocationList())
                {
                    if (((Plugin)item.Target).Name == name)
                    {
                        try
                        {
                            item.Method?.Invoke(item, new object[] { this, new PluginEnableEventArgs() });
                        }
                        catch (Exception e) { GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'."); if (!Plugins.ContainsKey(((Plugin)item.Target).Name)) { PluginEnableEvent -= item as EventHandler<PluginEnableEventArgs>; } }
                    }
                }
            }
        }
        public virtual Logger GetLogger(string signature)
        {
            return new Logger(signature);
        }
        public abstract void LoadPluginByFullName(string fullName);



        public event EventHandler<UserSendMessageEventArgs> UserSendMessageEvent;
        public void onUserSendMessageEvent(UserSendMessageEventArgs eventArgs)
        {
            if (UserSendMessageEvent == null) return;
            foreach (var item in UserSendMessageEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        UserSendMessageEvent -= item as EventHandler<UserSendMessageEventArgs>;
                    }
                }
            }
        }
        public event EventHandler<UserSendGroupMessageEventArgs> UserSendGroupMessageEvent;
        public void onUserSendGroupMessageEvent(UserSendGroupMessageEventArgs eventArgs)
        {
            if (UserSendGroupMessageEvent == null) return;
            foreach (var item in UserSendGroupMessageEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        UserSendGroupMessageEvent -= item as EventHandler<UserSendGroupMessageEventArgs>;
                    }
                }
            }
        }
        public event EventHandler<UserSendUserMessageEventArgs> UserSendUserMessageEvent;
        public void onUserSendUserMessageEvent(UserSendUserMessageEventArgs eventArgs)
        {
            if (UserSendUserMessageEvent == null) return;
            foreach (var item in UserSendUserMessageEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        UserSendUserMessageEvent -= item as EventHandler<UserSendUserMessageEventArgs>;
                    }
                }
            }
        }
        public event EventHandler<UserLoginEventArgs> UserLoginEvent;
        public void onUserLogin(UserLoginEventArgs eventArgs)
        {
            if (UserLoginEvent == null) return;
            foreach (var item in UserLoginEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        UserLoginEvent -= item as EventHandler<UserLoginEventArgs>;
                    }
                }
            }
        }
        public event EventHandler<UserLogoutEventArgs> UserLogoutEvent;
        public void onUserLogout(UserLogoutEventArgs eventArgs)
        {
            if (UserLogoutEvent == null) return;
            foreach (var item in UserLogoutEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e) { GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception'{e}'."); if (!Plugins.ContainsKey(((Plugin)item.Target).Name)) { UserLogoutEvent -= item as EventHandler<UserLogoutEventArgs>; } }
            }
        }
        public event EventHandler<PluginEnableEventArgs> PluginEnableEvent;
        public void onPluginEnable(PluginEnableEventArgs eventArgs)
        {
            if (PluginEnableEvent == null) return;
            foreach (var item in PluginEnableEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception '{e.ToString()}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        PluginEnableEvent -= item as EventHandler<PluginEnableEventArgs>;
                    }
                }
            }
        }
        public event EventHandler<PluginDisableEventArgs> PluginDisableEvent;
        public void onPluginDisable(PluginDisableEventArgs eventArgs)
        {
            if (PluginDisableEvent == null) return;
            foreach (var item in PluginDisableEvent?.GetInvocationList())
            {
                try
                {
                    item.Method?.Invoke(item.Target, new object[] { this, eventArgs });
                }
                catch (Exception e)
                {
                    GetLogger("PluginManager").Warn($"'{item.Method.Name}'({item.Target.GetType().FullName}) causee an exception '{e.ToString()}'.");
                    if (!Plugins.ContainsKey(((Plugin)item.Target).Name))
                    {
                        PluginDisableEvent -= item as EventHandler<PluginDisableEventArgs>;
                    }
                }
            }
        }
        public class Logger
        {
#nullable enable
            string signature;
            static StreamWriter? writer = null;
            public static void Exit()
            {
                writer.Close();
            }
            public Logger(string signature)
            {
                this.signature = signature;
                if (writer == null)
                {
                    string fn = "logs" + Path.DirectorySeparatorChar + DateTime.Now.ToString("yyyy-MM-dd");
                    for (int i = 1; ; i++)
                    {
                        if (!File.Exists($"{fn}-{i}.log"))
                        {
                            writer = new StreamWriter($"{fn}-{i}.log");
                            break;
                        }
                    }
                }
            }
            ~Logger()
            {
            }
            public void Info(string fmtstr, ConsoleColor color = ConsoleColor.Gray, params object?[] args)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.Write($"[{signature} {DateTime.Now.ToString("G")} INFO] ");
                writer.Write($"[{signature} {DateTime.Now.ToString("G")} INFO] ");
                Console.ForegroundColor = color;
                Console.WriteLine(fmtstr, args);
                writer.WriteLine(fmtstr, args);
                writer.Flush();
                Console.ResetColor();
            }
            public void Error(string fmtstr, params object?[] args)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.Write($"[{signature} {DateTime.Now.ToString("G")} ERROR] ");
                writer.Write($"[{signature} {DateTime.Now.ToString("G")} ERROR] ");
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(fmtstr, args);
                writer.WriteLine(fmtstr, args);
                writer.Flush();
                Console.ResetColor();
            }
            public void Warn(string fmtstr, params object?[] args)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.Write($"[{signature} {DateTime.Now.ToString("G")} WARN] ");
                writer.Write($"[{signature} {DateTime.Now.ToString("G")} WARN] ");
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(fmtstr, args);
                writer.WriteLine(fmtstr, args);
                writer.Flush();
                Console.ResetColor();
            }
#nullable disable
        }
    }
}